#include "Animation.h"
#include "ImageManager.h"
#include "MemTrack.h"

namespace bs
{
	const int DEFAULT_INTERVAL = 30;

	Animation::Animation()
		: showing(false),  stopOnEnd(false), startFrame(0), endFrame(0), curFrame(0), loopCount(0),
		interval(DEFAULT_INTERVAL), timeCounter(0), alphaTrans(false), alphaInc(0), 
		curAlpha(0), alphaAnim(false), image(NULL), row(0), col(0)
	{
	}

	Animation::~Animation()
	{
		ImageManager::Instance().ReleaseImage(this->image);
	}

	void Animation::Start()
	{
		if(this->playing)
			return;
		
		this->playing = true;
		this->showing = false;
		this->paused = false;
		
		this->curFrame = this->startFrame;
		this->timeCounter = 0;

		this->curAlpha = this->alphaInc>0 ? 0 : 255;

		this->StartMovement();
	}

	void Animation::Update( int elapsed, float speedFactor /*= 1.0f*/ )
	{
		if(!this->playing || this->paused)
			return;

		this->Move(speedFactor);
		
		this->timeCounter += elapsed;
		if(this->timeCounter < this->interval)
			return;

		this->UpdateAlphaTrans();

		if(this->curFrame == this->endFrame)
		{
			if(this->loopCount >= 0)
			{
				-- this->loopCount;
				if(this->loopCount < 0)
				{
					this->playing = false;
					return;
				}
			}

			this->curFrame = this->startFrame;
		}
		else
		{
			this->timeCounter = 0;
			if(this->startFrame < this->endFrame)
			{
				++ this->curFrame;
			}
			else 
			{
				-- this->curFrame;
			}
		}
	}

	void Animation::Draw( HDC dc )
	{
		if(!this->visible)
			return;

		if(!this->playing && !this->stopOnEnd && !this->showing)
			return;
		
		if(!this->image)
			return;
		
		RECT src;
		src.left = this->curFrame % this->col * this->w;
		src.right = src.left + this->w;
		src.top = this->curFrame / this->col * this->h;
		src.bottom = src.top + this->h;
		
		RECT dst;
		dst.left = (int)this->x - this->w / 2;
		dst.right = dst.left + this->w;
		dst.top = (int)this->y - this->h / 2;
		dst.bottom = dst.top + this->h;

		if(this->alphaTrans)
		{
			this->image->AlphaBlend(dc, dst, src, this->curAlpha);
		}
		else
		{
			this->image->Draw(dc, dst, src);
		}
	}

	bool Animation::LoadFile( const char* name, int r, int c, bool mirror/* = false*/ )
    {
		if(!name || !::strlen(name) || r<1 || c<1)
			return false;

		ImageManager::Instance().ReleaseImage(this->image);

		this->image = ImageManager::Instance().GetImage(name, mirror);
		
		if(!this->image)
			return false;
		
		this->row = r;
		this->col = c;
		this->w = this->image->GetWidth() / this->col;
		this->h = this->image->GetHeight() / this->row;
		
		return true;
	}

	bool Animation::SetAniSeq( int start, int end, int loop /* = -1*/ )
	{
		if(this->playing)
			return false;
		
		if(!this->image || start<0 || end<0)
			return false;
		
		int cellCount = this->row * this->col;
		
		if(start>=cellCount || end>=cellCount)
			return false;
		
		this->startFrame = start;
		this->endFrame = end;
		this->loopCount = loop;
		
		return true;
	}

	void Animation::ReverseAniSeq()
	{
		int temp = this->startFrame;
		this->startFrame = this->endFrame;
		this->endFrame = temp;
	}

	bool Animation::SetAlphaTrans( int duration, bool inc /*= true*/, bool isAnim /*= true*/ )
    {
		if(this->interval<=0 || duration<this->interval)
			return false;

		this->alphaTrans = true;
		this->alphaAnim = isAnim;
		this->alphaInc = 255 / (duration/this->interval);

		if(!inc)
		{
			this->alphaInc = -this->alphaInc; 
		}

		if(this->alphaAnim)
		{
			this->loopCount = -1;
		}

		return true;
	}

	bool Animation::ShowFrame( int frame )
	{
		if(!this->image || frame<0 || frame>=this->row*this->col)
			return false;
		
		this->curFrame = frame;
		this->playing = false;
		this->showing = true;
		
		return true;
	}

	void Animation::UpdateAlphaTrans()
	{
		if(!this->alphaTrans)
			return;
		
		this->curAlpha += this->alphaInc;

		if(this->alphaInc > 0)
		{
			++ this->alphaInc;

			if(this->curAlpha >= 255)
			{
				this->curAlpha = 255;
				this->alphaTrans = false;

				if(this->alphaAnim)
				{
					this->playing = false;
					this->alphaAnim  = false;
				}
			}
		}
		else if(this->alphaInc < 0)
		{
			-- this->alphaInc;

			if(this->curAlpha <= 0)
			{
				this->curAlpha = 0;
				this->alphaTrans = false;
				this->playing = false;
				this->alphaAnim  = false;
			}
		}
	}
}